package net.wicp.tams.common.constant.dbType;

import java.io.Serializable;
import java.math.BigDecimal;
import java.sql.Types;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.ArrayUtils;

import net.wicp.tams.common.apiext.DateUtil;
import net.wicp.tams.common.apiext.StringUtil;

public enum BinlogType {
	/**
	 * <code>DECIMAL = 0;</code>
	 */
	DECIMAL(0, Types.DECIMAL, new String[] {}),
	/**
	 * <code>TINY = 1;</code>
	 */
	TINY(1, Types.TINYINT, new String[] { "tinyint" }),
	/**
	 * <code>SHORT = 2;</code>
	 */
	SHORT(2, Types.SMALLINT, new String[] { "smallint" }),
	/**
	 * <code>LONG = 3;</code>
	 */
	LONG(3, Types.INTEGER, new String[] { "int", "integer(int)" }),
	/**
	 * <code>FLOAT = 4;</code>
	 */
	FLOAT(4, Types.FLOAT, new String[] { "float" }),
	/**
	 * <code>DOUBLE = 5;</code>WW
	 */
	DOUBLE(5, Types.DOUBLE, new String[] { "real(double)", "double" }),
	/**
	 * <code>NULL = 6;</code>
	 */
	NULL(6, Types.NULL, new String[] {}),
	/**
	 * <code>TIMESTAMP = 7;</code>
	 */
	TIMESTAMP(7, Types.TIMESTAMP, new String[] {}),
	/**
	 * <code>LONGLONG = 8;</code>
	 */
	LONGLONG(8, Types.BIGINT, new String[] { "bigint" }),
	/**
	 * <code>INT24 = 9;</code>
	 */
	INT24(9, Types.INTEGER, new String[] { "mediumint" }),
	/**
	 * <code>DATE = 10;</code>
	 */
	DATE(10, Types.DATE, new String[] { "date" }),
	/**
	 * <code>TIME = 11;</code>
	 */
	TIME(11, Types.TIME, new String[] {}),
	/**
	 * <code>DATETIME = 12;</code>
	 */
	DATETIME(12, Types.DATE, new String[] {}),
	/**
	 * <code>YEAR = 13;</code>
	 */
	YEAR(13, Types.VARCHAR, new String[] { "year" }),
	/**
	 * <code>NEWDATE = 14;</code>
	 */
	NEWDATE(14, Types.VARCHAR, new String[] {}),
	/**
	 * <code>VARCHAR = 15;</code>
	 */
	VARCHAR(15, Types.VARCHAR, new String[] { "varchar", "varbinary", "varchar(8000)" }),
	/**
	 * <code>BIT = 16;</code>
	 */
	BIT(16, Types.BIT, new String[] { "bit" }),
	/**
	 * <code>TIMESTAMP2 = 17;</code>
	 */
	TIMESTAMP2(17, Types.TIMESTAMP, new String[] { "timestamp" }),
	/**
	 * <code>DATETIME2 = 18;</code>
	 */
	DATETIME2(18, Types.DATE, new String[] { "datetime" }),
	/**
	 * <code>TIME2 = 19;</code>
	 */
	TIME2(19, Types.TIME, new String[] { "time" }),
	/**
	 * <code>JSON = 245;</code>
	 */
	JSON(245, Types.VARCHAR, new String[] {}),
	/**
	 * <code>NEWDECIMAL = 246;</code>
	 */
	NEWDECIMAL(246, Types.DECIMAL, new String[] { "decimal", "numeric(decimal)" }),
	/**
	 * <code>ENUM = 247;</code>
	 */
	ENUM(247, Types.VARCHAR, new String[] {}),
	/**
	 * <code>SET = 248;</code>
	 */
	SET(248, Types.VARCHAR, new String[] {}),
	/**
	 * <code>TINY_BLOB = 249;</code>
	 */
	TINY_BLOB(249, Types.BLOB, new String[] {}),
	/**
	 * <code>MEDIUM_BLOB = 250;</code>
	 */
	MEDIUM_BLOB(250, Types.BLOB, new String[] {}),
	/**
	 * <code>LONG_BLOB = 251;</code>
	 */
	LONG_BLOB(251, Types.BLOB, new String[] {}),
	/**
	 * <code>BLOB = 252;</code>
	 */
	BLOB(252, Types.BLOB, new String[] { "tinyblob", "blob", "mediumblob", "longblob", "tinytext", "text", "mediumtext",
			"longtext" }),
	/**
	 * <code>VAR_STRING = 253;</code>
	 */
	VAR_STRING(253, Types.VARCHAR, new String[] {}),
	/**
	 * <code>STRING = 254;</code>
	 */
	STRING(254, Types.VARCHAR, new String[] { "char", "enum('e3','e2','e1')", "set('s1','s3','s2')", "binary" }),
	/**
	 * <code>GEOMETRY = 255;</code>
	 */
	GEOMETRY(255, Types.VARCHAR, new String[] { "point", "linestring", "polygon", "geometry", "multipoint",
			"multilinestring", "multipolygon", "geometrycollection" }),

	UNRECOGNIZED(-1, Types.VARCHAR, new String[] {});

	private final int value;

	private final int types;

	private final String[] mysqlTypes;

	public int getValue() {
		return value;
	}

	private BinlogType(int value, int types, String[] mysqlTypes) {
		this.value = value;
		this.types = types;
		this.mysqlTypes = mysqlTypes;
	}

	public static BinlogType getByName(String mysqlType) {
		if (StringUtil.isNull(mysqlType)) {// 默认是任意匹配
			return UNRECOGNIZED;
		}
		for (BinlogType ele : BinlogType.values()) {
			if (ArrayUtils.contains(ele.getMysqlTypes(), mysqlType)) {
				return ele;
			}
		}
		return UNRECOGNIZED;
	}

	@SuppressWarnings("unchecked")
	public static <T extends Serializable> T getValue(BinlogType columnType, String value) {
		Serializable retobj = null;
		switch (columnType) {
		case LONGLONG:
			retobj = Long.valueOf(value);
			break;
		case BIT:
		case TINY:
		case SHORT:
		case INT24:
		case LONG:
		case ENUM:
		case SET:
			retobj = Integer.valueOf(value);
			break;
		case FLOAT:
			retobj = Float.valueOf(value);
			break;

		case DOUBLE:
			retobj = Double.valueOf(value);
			break;
		case DECIMAL:
		case NEWDECIMAL:
			retobj = new BigDecimal(value);
			break;
		case BLOB:
		case GEOMETRY:
			try {
				retobj = Base64.decodeBase64(value);
			} catch (Exception e) {
				retobj = value;
			}
			break;
		case YEAR:
			try {
				retobj = Integer.valueOf(value);
			} catch (Exception e) {
				retobj = value;
			}
			break;
		case DATE:
		case TIMESTAMP2:
		case DATETIME2:
			retobj = DateUtil.objToDate(value);
			break;

		default:
			retobj = value;
			break;
		}
		return (T) retobj;
	}

	public String[] getMysqlTypes() {
		return mysqlTypes;
	}

	public int getTypes() {
		return types;
	}
}
